// Ninf-G-XX, ver. 0.1
// Copyright 2011 National Institute of Advanced Industrial Science and Technology
// 
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// 
//     http://www.apache.org/licenses/LICENSE-2.0
// 
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#define DataNames_OWNER
#define ModeNames_OWNER

#include "ParamDesc.hpp"
#include "Exception.hpp"
#include "Arg.hpp"
#include "CallException.hpp"

using namespace ninf::lib;
ParamDesc :: ParamDesc(DataInputStream & dis) { // throws Exception
  EBEGIN { dataType = (DataType)dis.readInt();  } EEND
  EBEGIN { modeType = (ModeType)dis.readInt();  } EEND
  EBEGIN { nDim     = dis.readInt();              } EEND
  dim = new ParamDim *[nDim];
  for (int i = 0; i < nDim; i++){
    EBEGIN { dim[i] = new ParamDim(dis); } EEND
  }
}

ParamDesc :: ParamDesc(
    DataType dataType,
    ModeType modeType,
    int nDim,
    ParamDim ** dim)
  : dataType(dataType), modeType(modeType), nDim(nDim), dim(dim) {}

void 
ParamDesc :: writeTo(DataOutputStream & dos){
  EBEGIN { dos.writeInt((int) dataType);  } EEND
  EBEGIN { dos.writeInt((int) modeType);  } EEND

  EBEGIN { dos.writeInt(nDim);            } EEND
  for (int i = 0; i < nDim; i++){
      EBEGIN { dim[i]->writeTo(dos); } EEND
  }
}

#define PUTTAB(fp,tab)   { for (int i = 0; i < tab; i++) fprintf(fp, "\t");}

void
ParamDesc :: writeDeclaration(int tab, int index0, int index1, FILE * fp){
  for (int i = 0; i < nDim; i++){
    dim[i]->writeDeclaration(tab, index0, index1, i, fp);
  }

  PUTTAB(fp, tab);
  fprintf(fp, "ParamDim ** dims_%d_%d = new ParamDim * [%d];",
	  index0, index1, nDim);
  fprintf(fp, "\n");

  for (int i = 0; i < nDim; i++){
    PUTTAB(fp, tab);
    fprintf(fp, "dims_%d_%d[%d] = &dim_%d_%d_%d;", 
	    index0, index1, i, index0, index1, i);
    fprintf(fp, "\n");
  }

  PUTTAB(fp, tab);
  fprintf(fp, "ParamDesc desc_%d_%d(%s, %s, %d, dims_%d_%d);",
	  index0, index1,
	  DataNames[(int)dataType],
	  ModeNames[(int)modeType],
	  nDim, index0, index1);

  fprintf(fp, "\n");
}

void 
ParamDesc :: setupArg(va_list * app, Arg * arg){
  arg->dataType = dataType;
  arg->modeType = modeType;
  arg->nDim     = nDim;

  if (nDim == 0) {  // for scalar arg
    switch (dataType){
    case DT_CHAR:
      arg->v.c = (char)  va_arg(*app, int);     break;
    case DT_SHORT:
      arg->v.s = (short) va_arg(*app, int);     break;
    case DT_INT:
      arg->v.i = (int)   va_arg(*app, int);     break;
    case DT_LONG:
      arg->v.l = (long)  va_arg(*app, long);    break;
    case DT_FLOAT:
      arg->v.f = (float) va_arg(*app, double);  break;
    case DT_DOUBLE:
      arg->v.d = (double)va_arg(*app, double);  break;
    case DT_FILENAME:
      arg->v.p =         va_arg(*app, void *);  break;
    case DT_STRING_TYPE:
      arg->v.p =         va_arg(*app, void *);  break;
    default:
      CALL_EXCEPTION("the type is not supported for scalar arg", 
		     NINF_INTERNAL_ERROR);
    }
  }  else  {   // for vector arg
    arg->v.p = va_arg(*app, void *);
  }
}
